package com.jzsk.variable.center.common.utils.redis;

import redis.clients.jedis.*;
import redis.clients.jedis.params.GeoRadiusParam;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 操作redis工具类
 *
 * @author jiangli  2017/9/28
 * @version v1.0
 */
public class JedisUtil {

    public Server SERVER = new Server();
    public Keys KEYS = new Keys();
    public Strings STRINGS = new Strings();
    public Hashes HASHES = new Hashes();
    public Lists LISTS = new Lists();
    public Sets SETS = new Sets();
    public SortedSet SORTEDSET = new SortedSet();
    public PubSub PUBSUB = new PubSub();

    public Geo GEO = new Geo();
    public HyperLogLog HYPERLOGLOG = new HyperLogLog();

    public Transactions TRANSACTIONS = new Transactions();

    private final JedisPool jedisPool;

    public JedisUtil(String fileName) {
        JedisPoolFactory poolFactory = JedisPoolFactory.getInstance();
        this.jedisPool = poolFactory.getJedisPool(fileName);
    }

    public JedisUtil(JedisConfig jedisConfig){
        JedisPoolFactory poolFactory = JedisPoolFactory.getInstance();
        this.jedisPool = poolFactory.getJedisPool(jedisConfig);
    }

    /**
     * 从jedisPool中获取jedis对象
     *
     * @return Jedis对象
     */
    public Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 回收jedis对象
     *
     * @param jedis Jedis对象
     */
    public void closeJedis(Jedis jedis) {
        if (jedis != null && jedisPool != null) {
            jedis.close();
        }
    }

    /**
     * Server group
     */
    public class Server {

        /**
         * 清空所有keys
         *
         * @return 总返回ok
         */
        public String flushAll() {
            Jedis jedis = getJedis();
            String status = jedis.flushAll();
            closeJedis(jedis);
            return status;
        }

    }


    /**
     * Keys group
     */
    public class Keys {

        public void copy() {

        }

        /**
         * 删除key
         *
         * @param key 键
         */
        public long del(String key) {
            Jedis jedis = getJedis();
            long effect = jedis.del(key);
            closeJedis(jedis);
            return effect;
        }

        /**
         * 序列化给定的key值
         * 序列化的值会包含rdb版本信息，但不包含任何生存时间信息
         * 反序列化需保持版本一致
         *
         * @param key 键
         * @return 字节数组
         */
        public byte[] dump(String key) {
            Jedis jedis = getJedis();
            byte[] bytes = jedis.dump(key);
            closeJedis(jedis);
            return bytes;
        }

        /**
         * 检查给定的key是否存在
         *
         * @param key 键
         * @return true，键存在；false，键不存在
         */
        public boolean exists(String key) {
            Jedis jedis = getJedis();
            boolean exist = jedis.exists(key);
            closeJedis(jedis);
            return exist;
        }

        /**
         * 设置key过期时间，单位秒
         *
         * @param key     键
         * @param seconds 秒
         * @return 1为设置成功，0key不存在或设置失败
         */
        public long expire(String key, int seconds) {
            if (seconds <= 0) {
                return 0L;
            }
            Jedis jedis = getJedis();
            long status = jedis.expire(key, seconds);
            closeJedis(jedis);
            return status;
        }

        /**
         * 设置过期，时间为unix时间戳
         *
         * @param key      键
         * @param unixTime unix时间，秒级别
         * @return 1为设置成功，0key不存在或设置失败
         */
        public long expireAt(String key, long unixTime) {
            Jedis jedis = getJedis();
            long status = jedis.expireAt(key, unixTime);
            closeJedis(jedis);
            return status;
        }

        /**
         * 查找所有符合给定模式 pattern 的 key
         *
         * @param pattern 模式表达式
         * @return 返回匹配的键集合
         */
        public Set<String> keys(String pattern) {
            Jedis jedis = getJedis();
            Set<String> keys = jedis.keys(pattern);
            closeJedis(jedis);
            return keys;
        }

        /**
         * 将 key 原子性地从当前实例传送到目标实例的指定数据库上，一旦传送成功， key 保证会出现在目标实例上，而当前实例上的 key 会被删除。
         *
         * @param host          主机
         * @param port          端口号
         * @param key           key
         * @param destinationDb 目标db
         * @param timeout       超时时间，毫秒
         * @return 成功返回ok，key不存在返回NOKEY
         */
        public String migrate(String host, int port, String key, int destinationDb, int timeout) {
            Jedis jedis = getJedis();
            String status = jedis.migrate(host, port, key, destinationDb, timeout);
            closeJedis(jedis);
            return status;
        }

        /**
         * 将当前数据库的 key 移动到给定的数据库 db 当中。
         *
         * @param key    key
         * @param destDb 指定db
         * @return 1表示移动成功，0表示移动失败
         */
        public long move(String key, int destDb) {
            Jedis jedis = getJedis();
            long status = jedis.move(key, destDb);
            closeJedis(jedis);
            return status;
        }

        /**
         * 返回引用key对应值的数量
         *
         * @param key key
         * @return 引用数量
         */
        public Long objectRefcount(String key) {
            Jedis jedis = getJedis();
            Long refcount = jedis.objectRefcount(key);
            closeJedis(jedis);
            return refcount;
        }

        /**
         * 返回用于存储与键相关联的值的内部表示的类型。
         *
         * @param key key
         * @return 类型
         */
        public String objectEncoding(String key) {
            Jedis jedis = getJedis();
            String encoding = jedis.objectEncoding(key);
            closeJedis(jedis);
            return encoding;
        }

        /**
         * 返回key存储的值未被读或写操作访问的空闲时间
         * 前提条件：设置了maxmemory，并且缓存淘汰策略为LRU或者noeviction
         * redis默认策略为noeviction
         *
         * @param key key
         * @return 时间，单位秒
         */
        public Long objectIdleTime(String key) {
            Jedis jedis = getJedis();
            Long idleTime = jedis.objectIdletime(key);
            closeJedis(jedis);
            return idleTime;
        }

        /**
         * 返回对key存储值的访问频率
         * maxmemory-policy 为LFU策略可用
         *
         * @param key key
         * @return 访问频率记数
         */
        public Long objectFreq(String key) {
            Jedis jedis = getJedis();
            Long count = jedis.objectFreq(key);
            closeJedis(jedis);
            return count;
        }

        /**
         * 查看帮助
         *
         * @return 返回简洁的帮助文档
         */
        public List<String> objectHelp() {
            Jedis jedis = getJedis();
            List<String> helpList = jedis.objectHelp();
            closeJedis(jedis);
            return helpList;
        }

        /**
         * 查看帮助
         *
         * @return 返回简洁的帮助文档
         */
        public List<byte[]> objectHelpBinary() {
            Jedis jedis = getJedis();
            List<byte[]> helpList = jedis.objectHelpBinary();
            closeJedis(jedis);
            return helpList;
        }

        /**
         * 移除key的失效时间，将易失的key转换为永久的key
         *
         * @param key key
         * @return 1表示生存时间移除成功，0表示key不存在或key没有设置生存时间
         */
        public long persist(String key) {
            Jedis jedis = getJedis();
            long status = jedis.persist(key);
            closeJedis(jedis);
            return status;
        }

        /**
         * 以毫秒为单位设置key的有效期
         *
         * @param key          key
         * @param milliseconds 毫秒
         * @return 1设置成功，0key不存在或者设置失败
         */
        public long pExpire(String key, long milliseconds) {
            Jedis jedis = getJedis();
            long status = jedis.pexpire(key, milliseconds);
            closeJedis(jedis);
            return status;
        }

        /**
         * 以毫秒为单位设置 key 的过期 unix 时间戳
         *
         * @param key                   key
         * @param millisecondsTimestamp 毫秒级别的时间戳
         * @return 1设置成功，0表示key不存在或者设置失败
         */
        public long pExpireAt(String key, long millisecondsTimestamp) {
            Jedis jedis = getJedis();
            long status = jedis.pexpireAt(key, millisecondsTimestamp);
            closeJedis(jedis);
            return status;
        }

        /**
         * 以毫秒级返回key的剩余生存时间
         *
         * @param key key
         * @return key不存在返回-2，key存在但没有设置生存时间返回-1，否则以毫秒为单位返回key的剩余生存时间
         */
        public long pttl(String key) {
            Jedis jedis = getJedis();
            long time = jedis.pttl(key);
            closeJedis(jedis);
            return time;
        }

        /**
         * 从当前数据库中随机返回(不删除)一个 key
         *
         * @return 当数据库不为空时随机返回一个key，当数据库为空时返回nil
         */
        public String randomKey() {
            Jedis jedis = getJedis();
            String key = jedis.randomKey();
            closeJedis(jedis);
            return key;
        }

        /**
         * 将 oldKey 改名为 newKey 。
         * 当 oldKey 和 newKey 相同，或者 oldKey 不存在时，返回一个错误
         * 当 newKey 已经存在时， RENAME 命令将覆盖旧值
         *
         * @param oldKey oldKey
         * @param newKey newKey
         * @return 状态码，改名成功返回OK，失败返回错误提示
         */
        public String rename(String oldKey, String newKey) {
            Jedis jedis = getJedis();
            String status = jedis.rename(oldKey, newKey);
            closeJedis(jedis);
            return status;
        }

        /**
         * 当且仅当 newKey 不存在时，将 oldKey 改名为 newKey
         *
         * @param oldKey oldKey
         * @param newKey newKey
         * @return 更改成功返回1，newKey存在是返回0
         */
        public long renameNx(String oldKey, String newKey) {
            Jedis jedis = getJedis();
            long status = jedis.renamenx(oldKey, newKey);
            closeJedis(jedis);
            return status;
        }

        /**
         * 反序列化给定的序列化值，并将它和给定的 key 关联
         *
         * @param key   key
         * @param ttl   以毫秒为单位设置key的生存时间，如果ttl=0，那么不设置生存时间
         * @param bytes 序列化值
         * @return 反序列化成功返回OK，失败返回错误提示。
         */
        public String restore(String key, int ttl, byte[] bytes) {
            Jedis jedis = getJedis();
            String status = jedis.restore(key, ttl, bytes);
            closeJedis(jedis);
            return status;
        }

        public ScanResult<String> scan(String cursor) {
            Jedis jedis = getJedis();
            ScanResult<String> scan = jedis.scan(cursor);
            closeJedis(jedis);
            return scan;
        }

        public void sort() {

        }

        public void touch() {

        }

        /**
         * 以秒为单位，返回给定 key 的剩余生存时间(TTL, time to live)
         *
         * @param key key
         * @return key不存在返回-2，key存在但没有设置剩余时间返回-1，否则返回秒级剩余时间
         */
        public long ttl(String key) {
            Jedis jedis = getJedis();
            long time = jedis.ttl(key);
            closeJedis(jedis);
            return time;
        }

        /**
         * 返回 key 所储存的值的类型
         * none (key不存在)
         * string (字符串)
         * list (列表)
         * set (集合)
         * zset (有序集)
         * hash (哈希表)
         * stream (流)
         *
         * @param key key
         * @return key存储值的类型
         */
        public String type(String key) {
            Jedis jedis = getJedis();
            String type = jedis.type(key);
            closeJedis(jedis);
            return type;
        }

        /**
         * 删除key，和del命令一样都是删除key，不同的是unlink是在不同的线程里解除key与key值占用空间的关联，而del是同步阻塞的
         *
         * @param keys keys
         * @return 删除的key个数
         */
        public Long unlink(String... keys) {
            Jedis jedis = getJedis();
            Long count = jedis.unlink(keys);
            closeJedis(jedis);
            return count;
        }

        public void doWait() {

        }


    }

    /**
     * Strings group
     */
    public class Strings {

        /**
         * 在key存储的value值后追加内容
         *
         * @param key   key
         * @param value key存储的value值
         * @return 追加value后，key中字符串的长度
         */
        public long append(String key, String value) {
            Jedis jedis = getJedis();
            long length = jedis.append(key, value);
            jedis.close();
            return length;
        }

        /**
         * 计算给定字符串中，被设置为 1 的比特位的数量
         *
         * @param key key
         * @return 被设置为1的位的数量
         */
        public long bitCount(String key) {
            Jedis jedis = getJedis();
            long length = jedis.bitcount(key);
            jedis.close();
            return length;
        }

        /**
         * 计算给定字符串中，被设置为 1 的比特位的数量
         * 指定额外的 start 或 end 参数，可以让计数只在特定的位上进行
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public long bitCount(String key, int start, int end) {
            Jedis jedis = getJedis();
            long length = jedis.bitcount(key, start, end);
            jedis.close();
            return length;
        }

        public List<Long> bitField(String key, String args) {
            Jedis jedis = getJedis();
            List<Long> bitfield = jedis.bitfield(key, args);
            jedis.close();
            return bitfield;
        }

        public Long bitOp(BitOP bitOP, String destKet, String... srcKeys) {
            Jedis jedis = getJedis();
            Long bitOp = jedis.bitop(bitOP, destKet, srcKeys);
            jedis.close();
            return bitOp;
        }


        public Long bitPos(String key, boolean value) {
            Jedis jedis = getJedis();
            Long bitPos = jedis.bitpos(key, value);
            jedis.close();
            return bitPos;
        }

        /**
         * 将 key 中储存的数字值减一
         * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECR 操作。
         * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。
         *
         * @param key key
         * @return decr后的值
         */
        public long decr(String key) {
            Jedis jedis = getJedis();
            long value = jedis.decr(key);
            jedis.close();
            return value;
        }

        /**
         * 将 key 所储存的值减去减量 decrement
         *
         * @param key   key
         * @param count 减去的值
         * @return key所存储的值减去count后得到的值
         */
        public long decrBy(String key, long count) {
            Jedis jedis = getJedis();
            long value = jedis.decrBy(key, count);
            jedis.close();
            return value;
        }

        /**
         * 返回 key 所关联的字符串值
         *
         * @param key key
         * @return key对应的值
         */
        public String get(String key) {
            Jedis jedis = getJedis();
            String value = jedis.get(key);
            jedis.close();
            return value;
        }

        /**
         * 对key所储存的字符串值，获取指定偏移量上的位(bit)，如果位为1，则返回true
         *
         * @param key    key
         * @param offset 漂移量
         * @return 字符串值指定偏移量上的位，如果为1，则返回true
         */
        public boolean getBit(String key, long offset) {
            Jedis jedis = getJedis();
            boolean value = jedis.getbit(key, offset);
            jedis.close();
            return value;
        }

        /**
         * 返回 key 中字符串值的子字符串，字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
         *
         * @param key   key
         * @param start 起始偏移量
         * @param end   结束偏移量
         * @return 截取得到子字符串
         */
        public String getRange(String key, long start, long end) {
            Jedis jedis = getJedis();
            String value = jedis.getrange(key, start, end);
            jedis.close();
            return value;
        }

        /**
         * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
         * 原子操作
         *
         * @param key   key
         * @param value 新值
         * @return 返回给定key的旧值，key不存在时返回nil
         */
        public String getSet(String key, String value) {
            Jedis jedis = getJedis();
            String ret = jedis.getSet(key, value);
            jedis.close();
            return ret;
        }

        /**
         * 将 key 中储存的数字值增一
         * 该操作为原子操作
         *
         * @param key key
         * @return 执行incr后的key的值
         */
        public long incr(String key) {
            Jedis jedis = getJedis();
            long ret = jedis.incr(key);
            jedis.close();
            return ret;
        }

        /**
         * 将 key 所储存的值加上增量 increment
         *
         * @param key   key
         * @param count 增量值
         * @return 返回加上count后的key的值
         */
        public long incrBy(String key, long count) {
            Jedis jedis = getJedis();
            long ret = jedis.incrBy(key, count);
            jedis.close();
            return ret;
        }

        /**
         * 为 key 中所储存的值加上浮点数增量 increment
         *
         * @param key      key
         * @param increase 增量值
         * @return 执行命令之后的key的值
         */
        public double incrByFloat(String key, double increase) {
            Jedis jedis = getJedis();
            double ret = jedis.incrByFloat(key, increase);
            jedis.close();
            return ret;
        }

        /**
         * 返回所有(一个或多个)给定 key 的值
         *
         * @param keys keys
         * @return keys对应值列表
         */
        public List<String> mGet(String... keys) {
            Jedis jedis = getJedis();
            List<String> ret = jedis.mget(keys);
            jedis.close();
            return ret;
        }

        /**
         * 同时设置一个或多个 key-value 对
         * MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
         *
         * @param keyValuePair 键值对
         * @return 成功返回ok
         */
        public String mSet(String... keyValuePair) {
            Jedis jedis = getJedis();
            String status = jedis.mset(keyValuePair);
            jedis.close();
            return status;
        }

        /**
         * 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
         * 即使只有一个给定 key 已存在， MSETNX 也会拒绝执行所有给定 key 的设置操作
         *
         * @param keyValuePair 键值对
         * @return 当所有的key都设置成功返回1，存在一个失败（至少有一个key已经存在）返回0，原有其他key不变
         */
        public long mSetNx(String... keyValuePair) {
            Jedis jedis = getJedis();
            long status = jedis.msetnx(keyValuePair);
            jedis.close();
            return status;
        }

        /**
         * 这个命令和 SETEX 命令相似，但它以毫秒为单位设置 key 的生存时间，而不是像 SETEX 命令那样，以秒为单位
         * PSETEX mykey 1000 "Hello"
         *
         * @param key          key
         * @param milliseconds 毫秒时间
         * @param value        key存储值
         * @return 设置成功时返回ok
         */
        public String pSetEx(String key, long milliseconds, String value) {
            Jedis jedis = getJedis();
            String status = jedis.psetex(key, milliseconds, value);
            jedis.close();
            return status;
        }

        /**
         * 将key对应的值设置成value，并且丢弃先前的失效时间
         *
         * @param key   key
         * @param value value
         * @return 设置成功返回ok
         */
        public String set(String key, String value) {
            Jedis jedis = getJedis();
            String status = jedis.set(key, value);
            jedis.close();
            return status;
        }

        /**
         * 对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)
         * 位的设置或清除取决于 value 参数，可以是 0 也可以是 1
         * 当 key 不存在时，自动生成一个新的字符串值
         * 字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时，空白位置以 0 填充
         *
         * @param key    key
         * @param offset 偏移量
         * @param value  位值
         * @return 指定偏移量原来储存的位
         */
        public boolean setBit(String key, long offset, String value) {
            Jedis jedis = getJedis();
            boolean status = jedis.setbit(key, offset, value);
            jedis.close();
            return status;
        }

        /**
         * 将值 value 关联到 key ，并将 key 的生存时间设为 seconds (以秒为单位)
         *
         * @param key     key
         * @param seconds 失效时间
         * @param value   key存储值
         * @return 成功返回OK
         */
        public String setEx(String key, int seconds, String value) {
            Jedis jedis = getJedis();
            String status = jedis.setex(key, seconds, value);
            jedis.close();
            return status;
        }

        /**
         * 将 key 的值设为 value ，当且仅当 key 不存在
         *
         * @param key   key
         * @param value key存储值
         * @return 设置成功返回1，设置失败返回0
         */
        public long setNx(String key, String value) {
            Jedis jedis = getJedis();
            long status = jedis.setnx(key, value);
            jedis.close();
            return status;
        }

        /**
         * 用 value 参数覆写(overwrite)给定 key 所储存的字符串值，从偏移量 offset 开始
         *
         * @param key    key
         * @param offset 开始覆写的偏移量
         * @param value  覆盖值
         * @return 被 SETRANGE 修改之后，字符串的长度
         */
        public long setRange(String key, long offset, String value) {
            Jedis jedis = getJedis();
            long status = jedis.setrange(key, offset, value);
            jedis.close();
            return status;
        }

        /**
         * since 6.0.0
         */
        public void strAlgo() {

        }

        /**
         * 返回 key 所储存的字符串值的长度
         * key不存在 返回0
         * key存储值不为字符串值，抛错
         *
         * @param key key
         * @return 当key不存在时返回0
         */
        public long strLen(String key) {
            Jedis jedis = getJedis();
            long length = jedis.strlen(key);
            jedis.close();
            return length;
        }

    }

    /**
     * Hashes group
     */
    public class Hashes {

        /**
         * 删除哈希表key中一个或多个指定的域，不存的域将被忽略
         *
         * @param key    key
         * @param fields field
         * @return 被成功移除的域的数量，不包括被忽略的域
         */
        public long hDel(String key, String... fields) {
            Jedis jedis = getJedis();
            long effect = jedis.hdel(key, fields);
            jedis.close();
            return effect;
        }

        /**
         * 查看哈希表key中，给定域field是否存在
         *
         * @param key   key
         * @param field field
         * @return 存在返回true，不存在返回false
         */
        public boolean hExists(String key, String field) {
            Jedis jedis = getJedis();
            boolean exists = jedis.hexists(key, field);
            jedis.close();
            return exists;
        }

        /**
         * 给定域的值
         *
         * @param key   key
         * @param field field
         * @return 域值
         */
        public String hGet(String key, String field) {
            Jedis jedis = getJedis();
            String value = jedis.hget(key, field);
            jedis.close();
            return value;
        }

        /**
         * 返回哈希表中所有域和域的值
         *
         * @param key key
         * @return 哈希表中所有的域和域的值
         */
        public Map<String, String> hGetAll(String key) {
            Jedis jedis = getJedis();
            Map<String, String> fieldValue = jedis.hgetAll(key);
            jedis.close();
            return fieldValue;
        }

        /**
         * 为哈希表key中的域field的值加上增量increment
         *
         * @param key       key
         * @param field     field
         * @param increment 增量
         * @return 执行命令后，哈希表key中域field的值
         */
        public long hIncrBy(String key, String field, long increment) {
            Jedis jedis = getJedis();
            long value = jedis.hincrBy(key, field, increment);
            jedis.close();
            return value;
        }

        /**
         * 为哈希表key中的域field加上浮点数增量increment
         *
         * @param key       key
         * @param field     field
         * @param increment 增量
         * @return 执行加法操作之后 field 域的值
         */
        public double hIncrByFloat(String key, String field, double increment) {
            Jedis jedis = getJedis();
            double value = jedis.hincrByFloat(key, field, increment);
            jedis.close();
            return value;
        }

        /**
         * 返回哈希表key中的所有域。
         *
         * @param key key
         * @return 哈希key中所有的域
         */
        public Set<String> hKeys(String key) {
            Jedis jedis = getJedis();
            Set<String> keys = jedis.hkeys(key);
            jedis.close();
            return keys;
        }

        /**
         * 返回哈希表key中域的数量
         *
         * @param key key
         * @return 域的数量
         */
        public long hLen(String key) {
            Jedis jedis = getJedis();
            long len = jedis.hlen(key);
            jedis.close();
            return len;
        }

        /**
         * 返回哈希表key中，一个或多个给定域的值
         *
         * @param key    key
         * @param fields fields
         * @return 值列表
         */
        public List<String> hMGet(String key, String... fields) {
            Jedis jedis = getJedis();
            List<String> values = jedis.hmget(key, fields);
            jedis.close();
            return values;
        }

        /**
         * 同时将多个field-value(域-值)对设置到哈希表key中
         *
         * @param key        key
         * @param fieldValue field-value pair
         */
        public String hMSet(String key, Map<String, String> fieldValue) {
            Jedis jedis = getJedis();
            String reply = jedis.hmset(key, fieldValue);
            jedis.close();
            return reply;
        }

        public List<Map.Entry<String, String>> hScan(String key, String cursor) {
            Jedis jedis = getJedis();
            ScanResult<Map.Entry<String, String>> scanResult = jedis.hscan(key, cursor);
            List<Map.Entry<String, String>> result = scanResult.getResult();
            jedis.close();
            return result;
        }

        /**
         * 将哈希表key中的域field的值设为value
         *
         * @param key   key
         * @param field field
         * @param value value
         * @return 如果field为新域，且值设置成功返回1；如果field已经存在且旧值被新值覆盖，则返回0
         */
        public long hSet(String key, String field, String value) {
            Jedis jedis = getJedis();
            Long effect = jedis.hset(key, field, value);
            jedis.close();
            return effect;
        }

        /**
         * 将哈希表key中的域field的值设置为value，当且仅当域field不存在
         *
         * @param key   key
         * @param field field
         * @param value value
         * @return 设置成功返回1，如果域已经存在且没有操作被执行，则返回0
         */
        public long hSetNx(String key, String field, String value) {
            Jedis jedis = getJedis();
            Long effect = jedis.hsetnx(key, field, value);
            jedis.close();
            return effect;
        }

        /**
         * 返回哈希表key中的域field的值的长度，key或field不存在时，返回0
         *
         * @param key   key
         * @param field field
         * @return 哈希key中field域的值的长度；key或field不存在时，返回0
         */
        public long hStrLen(String key, String field) {
            Jedis jedis = getJedis();
            Long len = jedis.hstrlen(key, field);
            jedis.close();
            return len;
        }

        /**
         * 返回哈希表key中所有域的值
         *
         * @param key key
         * @return 所有field的值
         */
        public List<String> hVals(String key) {
            Jedis jedis = getJedis();
            List<String> values = jedis.hvals(key);
            jedis.close();
            return values;
        }

    }

    public class Lists {

        /**
         * 以阻塞的形式，按顺序弹出首个非空key列表的首个元素
         * timeout阻塞超时时间，单位秒，0表示无限延长
         *
         * @param timeout
         * @param keys
         * @return 包含两个元素，第一个被弹出元素的key，第二个被弹出的元素的值
         */
        public List<String> blpop(int timeout, String... keys) {
            Jedis jedis = getJedis();
            List<String> blpop = jedis.blpop(timeout, keys);
            jedis.close();
            return blpop;
        }

        /**
         * 它是 RPOP 命令的阻塞版本
         *
         * @param timeout
         * @param keys
         * @return
         */
        public List<String> brpop(int timeout, String... keys) {
            Jedis jedis = getJedis();
            List<String> brpop = jedis.brpop(timeout, keys);
            jedis.close();
            return brpop;
        }

        /**
         * 是 RPOPLPUSH 的阻塞版本
         *
         * @param source
         * @param destination
         * @param timeout
         * @return 被弹出的元素
         */
        public String brpoplpush(String source, String destination, int timeout) {
            Jedis jedis = getJedis();
            String brpoplpush = jedis.brpoplpush(source, destination, timeout);
            jedis.close();
            return brpoplpush;
        }

        /**
         * 返回列表 key 中，下标为 index 的元素
         *
         * @param key
         * @param index
         * @return 列表中下标为 index 的元素
         */
        public String lindex(String key, long index) {
            Jedis jedis = getJedis();
            String lindex = jedis.lindex(key, index);
            jedis.close();
            return lindex;
        }

        /**
         * 将值value插入到列表key当中，位于值pivot之前或之后
         *
         * @param key
         * @param position
         * @param pivot
         * @param value
         * @return 命令执行成功，返回插入数据之后列表的长度；没有找到pivot返回-1；如果key不存在或者为空列表返回0
         */
        public long linsert(String key, ListPosition position, String pivot, String value) {
            Jedis jedis = getJedis();
            Long linsert = jedis.linsert(key, position, pivot, value);
            jedis.close();
            return linsert;
        }

        /**
         * 返回列表key的长度
         *
         * @param key
         * @return 列表key的长度
         */
        public long llen(String key) {
            Jedis jedis = getJedis();
            Long llen = jedis.llen(key);
            jedis.close();
            return llen;
        }

        /**
         * 移除并返回列表 key 的头元素
         *
         * @param key
         * @return 列表的头元素
         */
        public String lpop(String key) {
            Jedis jedis = getJedis();
            String lpop = jedis.lpop(key);
            jedis.close();
            return lpop;
        }

        /**
         * 将一个或多个值value插入到列表key的表头
         *
         * @param key
         * @param values
         * @return 列表key的长度
         */
        public long lpush(String key, String... values) {
            Jedis jedis = getJedis();
            Long lpush = jedis.lpush(key, values);
            jedis.close();
            return lpush;
        }

        /**
         * 将值value插入到列表key的表头，当且仅当key存在并且是一个列表
         *
         * @param key
         * @param values
         * @return 插入数据后列表的长度
         */
        public long lpushx(String key, String... values) {
            Jedis jedis = getJedis();
            Long lpushx = jedis.lpushx(key, values);
            jedis.close();
            return lpushx;
        }

        /**
         * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定
         *
         * @param key
         * @param start
         * @param end
         * @return 指定区间元素列表
         */
        public List<String> lrange(String key, long start, long end) {
            Jedis jedis = getJedis();
            List<String> lrange = jedis.lrange(key, start, end);
            jedis.close();
            return lrange;
        }

        /**
         * 根据参数 count 的值，移除列表中与参数 value 相等的元素
         *
         * @param key
         * @param count
         * @param value
         * @return 被移除元素的数量
         */
        public long lrem(String key, long count, String value) {
            Jedis jedis = getJedis();
            Long lrem = jedis.lrem(key, count, value);
            jedis.close();
            return lrem;
        }


        /**
         * 将列表 key 下标为 index 的元素的值设置为 value
         *
         * @param key
         * @param index
         * @param value
         */
        public void lset(String key, long index, String value) {
            Jedis jedis = getJedis();
            jedis.lset(key, index, value);
            jedis.close();
        }

        /**
         * 对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除
         *
         * @param key
         * @param start
         * @param end
         */
        public void ltrim(String key, long start, long end) {
            Jedis jedis = getJedis();
            jedis.ltrim(key, start, end);
            jedis.close();
        }

        /**
         * 移除并返回列表key的尾元素
         *
         * @param key
         * @return 列表的尾元素
         */
        public String rpop(String key) {
            Jedis jedis = getJedis();
            String rpop = jedis.rpop(key);
            jedis.close();
            return rpop;
        }

        /**
         * 命令 RPOPLPUSH 在一个原子时间内，执行以下两个动作：
         * 将列表 source 中的最后一个元素(尾元素)弹出，并返回给客户端。
         * 将 source 弹出的元素插入到列表 destination ，作为 destination 列表的的头元素。
         *
         * @param source
         * @param destination
         * @return source被弹出的元素
         */
        public String rpoplpush(String source, String destination) {
            Jedis jedis = getJedis();
            String rpoplpush = jedis.rpoplpush(source, destination);
            jedis.close();
            return rpoplpush;
        }

        /**
         * 将一个或多个值value插入到列表key的表尾(最右边)
         *
         * @param key
         * @param values
         * @return 插入数据后表的长度
         */
        public long rpush(String key, String... values) {
            Jedis jedis = getJedis();
            Long rpush = jedis.rpush(key, values);
            jedis.close();
            return rpush;
        }

        /**
         * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表
         *
         * @param key
         * @param values
         * @return 表的长度
         */
        public long rpushx(String key, String... values) {
            Jedis jedis = getJedis();
            Long rpushx = jedis.rpushx(key, values);
            jedis.close();
            return rpushx;
        }

    }

    /**
     * SSCAN
     */
    public class Sets {

        /**
         * 将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略
         * 假如 key 不存在，则创建一个只包含 member 元素作成员的集合。
         * 当 key 不是集合类型时，返回一个错误。
         *
         * @param key
         * @param members
         * @return 被添加到集合中的新元素的数量，不包括被忽略的元素
         */
        public long sadd(String key, String... members) {
            Jedis jedis = getJedis();
            Long sadd = jedis.sadd(key, members);
            jedis.close();
            return sadd;
        }

        /**
         * 返回集合key的基数(集合中元素的数量)
         *
         * @param key
         * @return key不存在时返回0
         */
        public long scard(String key) {
            Jedis jedis = getJedis();
            Long scard = jedis.scard(key);
            jedis.close();
            return scard;
        }

        /**
         * 返回一个集合的全部成员，该集合是第一个给定集合和后面所有给定集合之间的差集
         *
         * @param keys
         * @return
         */
        public Set<String> sdiff(String... keys) {
            Jedis jedis = getJedis();
            Set<String> sdiff = jedis.sdiff(keys);
            jedis.close();
            return sdiff;
        }

        /**
         * 这个命令的作用和SDIFF类似，但它将结果保存到 estination集合，而不是简单地返回结果集
         *
         * @param destination
         * @param keys
         * @return 结果集中的元素数量
         */
        public long sdiffstore(String destination, String... keys) {
            Jedis jedis = getJedis();
            Long sdiffstore = jedis.sdiffstore(destination, keys);
            jedis.close();
            return sdiffstore;
        }

        /**
         * 返回一个集合的全部成员，该集合是所有给定集合的交集
         *
         * @param keys
         * @return 交集成员的列表
         */
        public Set<String> sinter(String... keys) {
            Jedis jedis = getJedis();
            Set<String> sinter = jedis.sinter(keys);
            jedis.close();
            return sinter;
        }

        /**
         * 这个命令类似于SINTER命令，但它将结果保存到destination集合，而不是简单地返回结果集
         *
         * @param destination
         * @param keys
         * @return 结果集中的成员数量
         */
        public long sinterstore(String destination, String... keys) {
            Jedis jedis = getJedis();
            Long sinterstore = jedis.sinterstore(destination, keys);
            jedis.close();
            return sinterstore;
        }

        /**
         * 判断 member 元素是否集合 key 的成员
         *
         * @param key
         * @param member
         * @return
         */
        public boolean sismember(String key, String member) {
            Jedis jedis = getJedis();
            boolean sismember = jedis.sismember(key, member);
            jedis.close();
            return sismember;
        }

        /**
         * 返回集合 key 中的所有成员
         *
         * @param key
         * @return
         */
        public Set<String> smembers(String key) {
            Jedis jedis = getJedis();
            Set<String> smembers = jedis.smembers(key);
            jedis.close();
            return smembers;
        }

        /**
         * 将member元素从source集合移动到destination集合
         * 该操作为原子操作
         *
         * @param source
         * @param destination
         * @param member
         * @return
         */
        public long smove(String source, String destination, String member) {
            Jedis jedis = getJedis();
            Long smove = jedis.smove(source, destination, member);
            jedis.close();
            return smove;
        }

        /**
         * 移除并返回集合中的一个随机元素
         *
         * @param key
         * @return 被移除的元素
         */
        public String spop(String key) {
            Jedis jedis = getJedis();
            String spop = jedis.spop(key);
            jedis.close();
            return spop;
        }

        /**
         * 返回集合中的一个随机元素，并不移除元素
         *
         * @param key
         * @return
         */
        public String srandmember(String key) {
            Jedis jedis = getJedis();
            String srandmember = jedis.srandmember(key);
            jedis.close();
            return srandmember;
        }

        /**
         * 返回集合中count个随机元素列表
         *
         * @param key
         * @param count
         * @return
         */
        public List<String> srandmember(String key, int count) {
            Jedis jedis = getJedis();
            List<String> srandmember = jedis.srandmember(key, count);
            jedis.close();
            return srandmember;
        }

        /**
         * 移除集合中一个或多个member元素
         *
         * @param key
         * @param members
         * @return 被成功移除元素的数量
         */
        public long srem(String key, String... members) {
            Jedis jedis = getJedis();
            Long srem = jedis.srem(key, members);
            jedis.close();
            return srem;
        }

        /**
         * 返回一个集合的全部成员，该集合是所有给定集合的并集
         *
         * @param keys
         * @return 并集成员的列表
         */
        public Set<String> sunion(String... keys) {
            Jedis jedis = getJedis();
            Set<String> sunion = jedis.sunion(keys);
            jedis.close();
            return sunion;
        }

        /**
         * 这个命令类似于 SUNION 命令，但它将结果保存到 destination 集合，而不是简单地返回结果集
         *
         * @param destination
         * @param keys
         * @return 结果集中的元素数量
         */
        public long sunionstore(String destination, String keys) {
            Jedis jedis = getJedis();
            Long sunionstore = jedis.sunionstore(destination, keys);
            jedis.close();
            return sunionstore;
        }
    }

    /**
     * ZUNIONSTORE、ZINTERSTORE、ZSCAN
     */
    public class SortedSet {

        /**
         * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中
         *
         * @param key
         * @param score
         * @param member
         * @return 被成功添加的新成员的数量，不包括那些被更新的、已经存在的成员
         */
        public long zadd(String key, double score, String member) {
            Jedis jedis = getJedis();
            Long zadd = jedis.zadd(key, score, member);
            jedis.close();
            return zadd;
        }

        /**
         * 返回有序集 key 的基数
         *
         * @param key
         * @return
         */
        public long zcard(String key) {
            Jedis jedis = getJedis();
            Long zcard = jedis.zcard(key);
            jedis.close();
            return zcard;
        }

        /**
         * 返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
         *
         * @param key
         * @param min
         * @param max
         * @return score 值在 min 和 max 之间的成员的数量
         */
        public long zcount(String key, double min, double max) {
            Jedis jedis = getJedis();
            Long zcount = jedis.zcount(key, min, max);
            jedis.close();
            return zcount;
        }

        /**
         * 为有序集 key 的成员 member 的 score 值加上增量 increment
         *
         * @param key
         * @param increment
         * @param member
         * @return member 成员的新 score 值
         */
        public double zincrby(String key, double increment, String member) {
            Jedis jedis = getJedis();
            Double zincrby = jedis.zincrby(key, increment, member);
            jedis.close();
            return zincrby;
        }

        /**
         * 返回有序集 key 中，指定区间内的成员
         *
         * @param key
         * @param start
         * @param end
         * @return 指定区间内，带有 score 值(可选)的有序集成员的列表
         */
        public Set<String> zrange(String key, long start, long end) {
            Jedis jedis = getJedis();
            Set<String> zrange = jedis.zrange(key, start, end);
            jedis.close();
            return zrange;
        }

        /**
         * 返回有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Set<String> zrangebyscore(String key, double min, double max) {
            Jedis jedis = getJedis();
            Set<String> zrangeByScore = jedis.zrangeByScore(key, min, max);
            jedis.close();
            return zrangeByScore;
        }

        /**
         * 返回有序集 key 中成员 member 的排名
         *
         * @param key
         * @param member
         * @return 返回 member 的排名
         */
        public long zrank(String key, String member) {
            Jedis jedis = getJedis();
            Long zrank = jedis.zrank(key, member);
            jedis.close();
            return zrank;
        }

        /**
         * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略
         *
         * @param key
         * @param members
         * @return 被成功移除的成员的数量，不包括被忽略的成员
         */
        public long zrem(String key, String... members) {
            Jedis jedis = getJedis();
            Long zrem = jedis.zrem(key, members);
            jedis.close();
            return zrem;
        }

        /**
         * 移除有序集 key 中，指定排名(rank)区间内的所有成员
         *
         * @param key
         * @param start
         * @param end
         * @return 被移除成员的数量
         */
        public long zremrangebyrank(String key, long start, long end) {
            Jedis jedis = getJedis();
            Long aLong = jedis.zremrangeByRank(key, start, end);
            jedis.close();
            return aLong;
        }

        /**
         * 移除有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员
         *
         * @param key
         * @param min
         * @param max
         * @return 被移除成员的数量
         */
        public long zremrangebyscore(String key, double min, double max) {
            Jedis jedis = getJedis();
            Long aLong = jedis.zremrangeByScore(key, min, max);
            jedis.close();
            return aLong;
        }

        /**
         * 返回有序集 key 中，指定区间内的成员，其中成员的位置按 score 值递减(从大到小)来排列
         *
         * @param key
         * @param start
         * @param end
         * @return 指定区间内，带有 score 值(可选)的有序集成员的列表
         */
        public Set<String> zrevrange(String key, long start, long end) {
            Jedis jedis = getJedis();
            Set<String> zrevrange = jedis.zrevrange(key, start, end);
            jedis.close();
            return zrevrange;
        }

        /**
         * 返回有序集 key 中， score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列
         *
         * @param key
         * @param max
         * @param min
         * @return 指定区间内，带有 score 值(可选)的有序集成员的列表
         */
        public Set<String> zrevrangebyscore(String key, double max, double min) {
            Jedis jedis = getJedis();
            Set<String> strings = jedis.zrevrangeByScore(key, max, min);
            jedis.close();
            return strings;
        }

        /**
         * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序
         *
         * @param key
         * @param member
         * @return 返回 member 的排名
         */
        public long zrevrank(String key, String member) {
            Jedis jedis = getJedis();
            Long zrevrank = jedis.zrevrank(key, member);
            jedis.close();
            return zrevrank;
        }

        /**
         * 返回有序集 key 中，成员 member 的 score 值
         *
         * @param key
         * @param member
         * @return member 成员的 score 值
         */
        public double zscore(String key, String member) {
            Jedis jedis = getJedis();
            Double zscore = jedis.zscore(key, member);
            jedis.close();
            return zscore;
        }


    }


    /**
     * 发布/订阅
     */
    public class PubSub {


        /**
         * 发布，将信息message发送到指定的频道channel
         *
         * @param channel 频道
         * @param message 消息
         * @return 接收到信息message的订阅者数量
         */
        public long publish(String channel, String message) {
            Jedis jedis = getJedis();
            long publish = jedis.publish(channel, message);
            jedis.close();
            return publish;
        }

        /**
         * 订阅，订阅给定的一个或多个频道的信息
         * 阻塞式，other code只有在调用jedisPubSub.unsubscribe()取消订阅后才会执行
         *
         * @param jedisPubSub
         * @param channels
         */
        public void subscribe(JedisPubSub jedisPubSub, String... channels) {
            Jedis jedis = getJedis();
            jedis.subscribe(jedisPubSub, channels);
            //other code
        }

        /**
         * 订阅一个或多个符合给定模式的频道
         *
         * @param jedisPubSub 继承JedisPubSub并实现抽奖方法的类
         * @param patterns    匹配模式
         */
        public void psubscribe(JedisPubSub jedisPubSub, String... patterns) {
            Jedis jedis = getJedis();
            jedis.psubscribe(jedisPubSub, patterns);
        }

        /**
         * 查找当前活动的频道（至少有一个订阅者的频道）
         *
         * @param pattern 匹配模式
         * @return 频道列表
         */
        public List<String> pubsub(String pattern) {
            Jedis jedis = getJedis();
            List<String> pubsubChannels = jedis.pubsubChannels(pattern);
            jedis.close();
            return pubsubChannels;
        }

        /**
         * 返回给定频道的订阅者数量
         *
         * @param channels 频道
         * @return 返回给定频道的订阅者数量
         */
        public Map<String, String> pubsubnumsub(String... channels) {
            Jedis jedis = getJedis();
            Map<String, String> stringStringMap = jedis.pubsubNumSub(channels);
            jedis.close();
            return stringStringMap;
        }

        /**
         * 返回订阅模式的数量
         * 注意， 这个命令返回的不是订阅模式的客户端的数量， 而是客户端订阅的所有模式的数量总和
         *
         * @return 返回订阅模式的数量
         */
        public long pubsubnumpat() {
            Jedis jedis = getJedis();
            Long pubsubNumPat = jedis.pubsubNumPat();
            jedis.close();
            return pubsubNumPat;
        }

    }

    /**
     * Geo group
     */
    public class Geo {

        /**
         * 往定义的哈希key中加入地理空间记录
         *
         * @param key       key
         * @param longitude 经度
         * @param latitude  维度
         * @param member    地理空间名称
         * @return 成功插入返回1
         */
        public Long geoAdd(String key, double longitude, double latitude, String member) {
            Jedis jedis = getJedis();
            Long effect = jedis.geoadd(key, longitude, latitude, member);
            jedis.close();
            return effect;
        }

        /**
         * 往定义的哈希key中批量加入地理空间记录
         *
         * @param key                 key
         * @param memberCoordinateMap 地理空间map
         * @return 成功加入的记录数
         */
        public Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap) {
            Jedis jedis = getJedis();
            Long effect = jedis.geoadd(key, memberCoordinateMap);
            jedis.close();
            return effect;
        }

        /**
         * 计算两个地理空间的距离
         *
         * @param key    key
         * @param source 源地理
         * @param target 目的地理
         * @return 距离，默认单位：米
         */
        public Double geoDist(String key, String source, String target) {
            Jedis jedis = getJedis();
            Double distance = jedis.geodist(key, source, target);
            jedis.close();
            return distance;
        }

        /**
         * 计算两个地理空间的距离
         *
         * @param key    key
         * @param source 源地理
         * @param target 目的地理
         * @param unit   距离单位
         * @return 距离
         */
        public Double geoDist(String key, String source, String target, GeoUnit unit) {
            Jedis jedis = getJedis();
            Double distance = jedis.geodist(key, source, target, unit);
            jedis.close();
            return distance;
        }

        /**
         * 获取地理坐标的哈希值
         *
         * @param key     key
         * @param members members
         * @return 地址坐标哈希值列表
         */
        public List<String> geoHash(String key, String... members) {
            Jedis jedis = getJedis();
            List<String> hashes = jedis.geohash(key, members);
            jedis.close();
            return hashes;
        }

        /**
         * 获取地理坐标的经纬度值
         *
         * @param key     key
         * @param members members
         * @return 地理坐标的经纬度值
         */
        public List<GeoCoordinate> geoPos(String key, String... members) {
            Jedis jedis = getJedis();
            List<GeoCoordinate> pos = jedis.geopos(key, members);
            jedis.close();
            return pos;
        }

        /**
         * 获取key中在设定的地理坐标半径之内的所有坐标集合
         *
         * @param key       key
         * @param longitude 经度
         * @param latitude  维度
         * @param radius    半径
         * @param unit      单位
         * @return 返回坐标点（longitude,latitude）半径radius（单位：unit）范围内的地理坐标
         */
        public List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double radius,
                                                 GeoUnit unit) {
            Jedis jedis = getJedis();
            List<GeoRadiusResponse> pos = jedis.georadius(key, longitude, latitude, radius, unit);
            jedis.close();
            return pos;
        }

        /**
         * 获取key中在设定的地理坐标半径之内的所有坐标集合
         *
         * @param key       key
         * @param longitude 经度
         * @param latitude  维度
         * @param radius    半径
         * @param unit      单位
         * @param param     返回值选项参数
         * @return 返回坐标点（longitude,latitude）半径radius（单位：unit）范围内的地理坐标
         */
        public List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double radius,
                                                 GeoUnit unit, GeoRadiusParam param) {
            Jedis jedis = getJedis();
            List<GeoRadiusResponse> pos = jedis.georadius(key, longitude, latitude, radius, unit, param);
            jedis.close();
            return pos;
        }

        /**
         * 获取key中在设定的地理坐标半径之内的所有坐标集合
         *
         * @param key    key
         * @param member 地理坐标名
         * @param radius 半径
         * @param unit   单位
         * @return 返回坐标点（longitude,latitude）半径radius（单位：unit）范围内的地理坐标
         */
        public List<GeoRadiusResponse> geoRadiusByMember(String key, String member, double radius, GeoUnit unit) {
            Jedis jedis = getJedis();
            List<GeoRadiusResponse> pos = jedis.georadiusByMember(key, member, radius, unit);
            jedis.close();
            return pos;
        }

        /**
         * 获取key中在设定的地理坐标半径之内的所有坐标集合
         *
         * @param key    key
         * @param member 地理坐标名
         * @param radius 半径
         * @param unit   单位
         * @param param  返回值选项参数
         * @return 返回坐标点（longitude,latitude）半径radius（单位：unit）范围内的地理坐标
         */
        public List<GeoRadiusResponse> geoRadiusByMember(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param) {
            Jedis jedis = getJedis();
            List<GeoRadiusResponse> pos = jedis.georadiusByMember(key, member, radius, unit, param);
            jedis.close();
            return pos;
        }

    }

    /**
     * HyperLogLog
     */
    public class HyperLogLog {

        /**
         * 向键为key的HyperLogLog中添加元素
         *
         * @param key    key
         * @param values values
         */
        public void pfAdd(String key, String... values) {
            Jedis jedis = getJedis();
            jedis.pfadd(key, values);
            jedis.close();
        }

        /**
         * 统计键值为key的HyperLogLog中元素个数
         *
         * @param key key
         * @return 返回键值为key的hyperLogLog中元素的个数，近似值，有0.81%的偏差
         */
        public Long pfCount(String key) {
            Jedis jedis = getJedis();
            Long count = jedis.pfcount(key);
            jedis.close();
            return count;
        }

        /**
         * 合并多个HyperLogLog
         *
         * @param destKey    目标HyperLogLog
         * @param sourceKeys 源HyperLogLog
         * @return just return 'OK' string
         */
        public String pfMerge(String destKey, String... sourceKeys) {
            Jedis jedis = getJedis();
            String ret = jedis.pfmerge(destKey, sourceKeys);
            jedis.close();
            return ret;
        }

    }

    /**
     * Transactions group
     */
    public class Transactions {

        public List<Object> multi(Operation operation) {
            Jedis jedis = getJedis();
            Transaction multi = jedis.multi();
            operation.batchExec(multi);
            List<Object> exec = multi.exec();
            jedis.close();
            return exec;
        }

    }

    @FunctionalInterface
    public interface Operation {

        /**
         * 批量执行命令
         *
         * @param transaction 事务对象
         */
        void batchExec(Transaction transaction);

    }

}
